package com.chongchong.online.controller;

import cn.hutool.core.collection.CollUtil;
import cn.jimmyshi.beanquery.BeanQuery;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.chongchong.common.constant.ErrorCodeEnum;
import com.chongchong.common.tool.CommonUtil;
import com.chongchong.common.validator.UpdateGroup;
import com.chongchong.online.entity.*;
import com.chongchong.online.service.*;
import com.chongchong.online.wrapper.OnlineColumnWrapper;
import com.chongchong.online.wrapper.OnlineRuleWrapper;
import com.chongchong.core.mp.object.MyModelUtil;
import com.chongchong.core.mp.object.MyOrderParam;
import com.chongchong.core.mp.object.MyRelationParam;
import com.chongchong.core.mp.support.Query;
import com.chongchong.core.tool.api.R;
import com.chongchong.online.dto.OnlineColumnDto;
import com.chongchong.online.dto.OnlineColumnRuleDto;
import com.chongchong.online.dto.OnlineRuleDto;
import com.chongchong.online.entity.*;
import com.chongchong.online.object.SqlTableColumn;
import com.chongchong.online.service.*;
import com.chongchong.online.vo.OnlineColumnRuleVo;
import com.chongchong.online.vo.OnlineColumnVo;
import com.chongchong.online.vo.OnlineRuleVo;
import io.swagger.annotations.Api;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;

import javax.validation.groups.Default;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 字段数据操作控制器类。
 *
 * @author Jerry
 * @date 2021-06-06
 */
@Api(tags = "字段数据操作接口")
@RestController
@AllArgsConstructor
@RequestMapping("/onlinecolumn")
public class OnlineColumnController {

    private IOnlineColumnService onlineColumnService;
    private IOnlineTableService onlineTableService;
    private IOnlineVirtualColumnService onlineVirtualColumnService;
    private IOnlineDblinkService onlineDblinkService;
    private IOnlineRuleService onlineRuleService;

    /**
     * 根据数据库表字段信息，在指定在线表中添加在线表字段对象。
     *
//     * @param dblinkId   数据库链接Id。
//     * @param tableName  数据库表名称。
//     * @param columnName 数据库表字段名。
//     * @param tableId    目的表Id。
     * @return 应答结果对象。
     */
    @PostMapping("/save")
    public R<Void> add(
            @RequestBody Map<String, Object> columnMap) {
        OnlineDblink dblink = onlineDblinkService.getById(String.valueOf(columnMap.get("dblinkId")));
        if (dblink == null) {
            return R.fail(ErrorCodeEnum.DATA_NOT_EXIST.getErrorMessage());
        }
        String errorMsg;
        SqlTableColumn sqlTableColumn = onlineDblinkService.getDblinkTableColumn(dblink,
			String.valueOf(columnMap.get("tableName")), String.valueOf(columnMap.get("columnName")));
        if (sqlTableColumn == null) {
            errorMsg = "数据验证失败，指定的数据表字段不存在！";
            return R.fail(errorMsg);
        }
        if (onlineTableService.getById(Long.parseLong(String.valueOf(columnMap.get("tableId")))) == null) {
            errorMsg = "数据验证失败，指定的数据表Id不存在！";
            return R.fail(errorMsg);
        }
        onlineColumnService.saveNewList(CollUtil.newLinkedList(sqlTableColumn), Long.parseLong(String.valueOf(columnMap.get("tableId"))));
        return R.data(null);
    }

    /**
     * 更新字段数据数据。
     *
     * @param onlineColumnDto 更新对象。
     * @return 应答结果对象。
     */
    @PostMapping("/update")
    public R<Void> update(@RequestBody OnlineColumnDto onlineColumnDto) {
        String errorMessage = CommonUtil.getModelValidationError(onlineColumnDto, Default.class, UpdateGroup.class);
        if (errorMessage != null) {
            return R.fail(errorMessage);
        }
        OnlineColumn onlineColumn = MyModelUtil.copyTo(onlineColumnDto, OnlineColumn.class);
        OnlineColumn originalOnlineColumn = onlineColumnService.getById(onlineColumn.getColumnId());
        if (originalOnlineColumn == null) {
            errorMessage = "数据验证失败，当前在线表字段并不存在，请刷新后重试！";
            return R.fail(errorMessage);
        }
        // 验证关联Id的数据合法性
        R callResult = onlineColumnService.verifyRelatedData(onlineColumn, originalOnlineColumn);
        if (!callResult.isSuccess()) {
            errorMessage = callResult.getMsg();
            return R.fail(errorMessage);
        }
        if (!onlineColumnService.update(onlineColumn, originalOnlineColumn)) {
            return R.fail(ErrorCodeEnum.DATA_NOT_EXIST.getErrorMessage());
        }
        return R.data(null);
    }

    /**
     * 删除字段数据数据。
     *
     * @param columnId 删除对象主键Id。
     * @return 应答结果对象。
     */
    @PostMapping("/remove")
    public R<Void> delete(@RequestBody Long columnId) {
        String errorMessage;
        if (CommonUtil.existBlankArgument(columnId)) {
            return R.fail(ErrorCodeEnum.ARGUMENT_NULL_EXIST.getErrorMessage());
        }
        // 验证关联Id的数据合法性
        OnlineColumn originalOnlineColumn = onlineColumnService.getById(columnId);
        if (originalOnlineColumn == null) {
            errorMessage = "数据验证失败，当前在线表字段并不存在，请刷新后重试！";
            return R.fail(errorMessage);
        }
        OnlineVirtualColumn virtualColumnFilter = new OnlineVirtualColumn();
        virtualColumnFilter.setAggregationColumnId(columnId);
        List<OnlineVirtualColumn> virtualColumnList =
                onlineVirtualColumnService.getOnlineVirtualColumnList(virtualColumnFilter, null);
        if (CollUtil.isNotEmpty(virtualColumnList)) {
            OnlineVirtualColumn virtualColumn = virtualColumnList.get(0);
            errorMessage = "数据验证失败，数据源关联正在被虚拟字段 [" + virtualColumn.getColumnPrompt() + "] 使用，不能被删除！";
            return R.fail(errorMessage);
        }
        if (!onlineColumnService.remove(originalOnlineColumn.getTableId(), columnId)) {
            errorMessage = "数据操作失败，删除的对象不存在，请刷新后重试！";
            return R.fail(errorMessage);
        }
        return R.data(null);
    }

    /**
	 * 列出符合过滤条件的字段数据列表。
	 *
	 * @param onlineColumn 过滤对象。
	 * @param orderParam            排序参数。
	 * @param query             分页参数。
	 * @return 应答结果对象，包含查询结果集。
	 */
	@GetMapping("/list")
	public R<IPage<OnlineColumnVo>> list(OnlineColumn onlineColumn,
										 MyOrderParam orderParam, Query query) {
		String orderBy = MyOrderParam.buildOrderBy(orderParam, OnlineColumn.class);
		List<OnlineColumn> onlineColumnList = onlineColumnService.getOnlineColumnListWithRelation(onlineColumn, orderBy);

//		IPage<OnlineTable> pages = onlineTableService.page(Condition.getPage(query), Condition.getQueryWrapper(flowWorkOrder));

		IPage<OnlineColumn> pages = new Page<>(query.getCurrent(), query.getSize());
		pages.setRecords(onlineColumnList);

		return R.data(OnlineColumnWrapper.build().pageVO(pages));
	}

	/**
	 * 列出符合过滤条件的字段数据列表。
	 *
	 * @param onlineColumn 过滤对象。
	 * @return 应答结果对象，包含查询结果集。
	 */
	@GetMapping("/listNoPage")
	public R<List<OnlineColumnVo>> listNoPage(OnlineColumn onlineColumn) {
		List<OnlineColumn> onlineColumnList = onlineColumnService.getOnlineColumnListWithRelation(onlineColumn, null);
		return R.data(OnlineColumnWrapper.build().listVO(onlineColumnList));
	}

    /**
     * 查看指定字段数据对象详情。
     *
     * @param columnId 指定对象主键Id。
     * @return 应答结果对象，包含对象详情。
     */
    @GetMapping("/detail")
    public R<OnlineColumnVo> view(@RequestParam Long columnId) {
        if (CommonUtil.existBlankArgument(columnId)) {
            return R.fail(ErrorCodeEnum.ARGUMENT_NULL_EXIST.getErrorMessage());
        }
        OnlineColumn onlineColumn = onlineColumnService.getByIdWithRelation(columnId, MyRelationParam.full());
        if (onlineColumn == null) {
            return R.fail(ErrorCodeEnum.DATA_NOT_EXIST.getErrorMessage());
        }
        return R.data(OnlineColumnWrapper.build().entityVO(onlineColumn));
    }

    /**
     * 将数据库中的表字段信息刷新到已经导入的在线表字段信息。
     *
//     * @param dblinkId   数据库链接Id。
//     * @param tableName  数据库表名称。
//     * @param columnName 数据库表字段名。
//     * @param columnId   被刷新的在线字段Id。
     * @return 应答结果对象。
     */
    @PostMapping("/refresh")
    public R<Void> refresh(
            @RequestBody Map<String, Object> columnMap) {
        OnlineDblink dblink = onlineDblinkService.getById(String.valueOf(columnMap.get("dblinkId")));
        if (dblink == null) {
            return R.fail(ErrorCodeEnum.DATA_NOT_EXIST.getErrorMessage());
        }
        String errorMsg;
        SqlTableColumn sqlTableColumn = onlineDblinkService.getDblinkTableColumn(dblink,
			String.valueOf(columnMap.get("tableName")), String.valueOf(columnMap.get("columnName")));
        if (sqlTableColumn == null) {
            errorMsg = "数据验证失败，指定的数据表字段不存在！";
            return R.fail(errorMsg);
        }
        OnlineColumn onlineColumn = onlineColumnService.getById(String.valueOf(columnMap.get("columnId")));
        if (onlineColumn == null) {
            errorMsg = "数据验证失败，指定的在线表字段Id不存在！";
            return R.fail(errorMsg);
        }
        onlineColumnService.refresh(sqlTableColumn, onlineColumn);
        return R.data(null);
    }

    /**
     * 列出不与指定字段数据存在多对多关系的 [验证规则] 列表数据。通常用于查看添加新 [验证规则] 对象的候选列表。
     *
     * @param onlineColumn            主表关联字段。
     * @param onlineRuleDtoFilter [验证规则] 过滤对象。
     * @param orderParam          排序参数。
     * @param query           分页参数。
     * @return 应答结果对象，返回符合条件的数据列表。
     */
    @PostMapping("/listNotInOnlineColumnRule")
	public R<IPage<OnlineRuleVo>> listNotInOnlineColumnRule(OnlineColumn onlineColumn,
															@RequestBody OnlineRuleDto onlineRuleDtoFilter,
															@RequestBody MyOrderParam orderParam, Query query) {
		R<Void> verifyResult = this.doOnlineColumnRuleVerify(onlineColumn.getColumnId());
		if (!verifyResult.isSuccess()) {
			return R.fail(verifyResult.getMsg());
		}
		OnlineRule filter = MyModelUtil.copyTo(onlineRuleDtoFilter, OnlineRule.class);
		String orderBy = MyOrderParam.buildOrderBy(orderParam, OnlineRule.class);
		List<OnlineRule> onlineRuleList = onlineRuleService.getNotInOnlineRuleListByColumnId(onlineColumn.getColumnId(), filter, orderBy);

		IPage<OnlineRule> pages = new Page<>(query.getCurrent(), query.getSize());
		pages.setRecords(onlineRuleList);

		return R.data(OnlineRuleWrapper.build().pageVO(pages));
	}

	/**
	 * 列出不与指定字段数据存在多对多关系的 [验证规则] 列表数据。通常用于查看添加新 [验证规则] 对象的候选列表。
	 *
	 * @param onlineColumn            主表关联字段。
	 * @return 应答结果对象，返回符合条件的数据列表。
	 */
	@PostMapping("/listNotInOnlineColumnRuleNoPage")
	public R<List<OnlineRuleVo>> listNotInOnlineColumnRuleNoPage(OnlineColumn onlineColumn) {
		R<Void> verifyResult = this.doOnlineColumnRuleVerify(onlineColumn.getColumnId());
		if (!verifyResult.isSuccess()) {
			return R.fail(verifyResult.getMsg());
		}
		List<OnlineRule> onlineRuleList = onlineRuleService.getNotInOnlineRuleListByColumnId(onlineColumn.getColumnId(), null, null);

		return R.data(OnlineRuleWrapper.build().listVO(onlineRuleList));
	}

    /**
     * 列出与指定字段数据存在多对多关系的 [验证规则] 列表数据。
     *
     * @param onlineColumn            主表关联字段。
     * @param onlineRuleDtoFilter [验证规则] 过滤对象。
     * @param orderParam          排序参数。
     * @param query           分页参数。
     * @return 应答结果对象，返回符合条件的数据列表。
     */
    @PostMapping("/listOnlineColumnRule")
	public R<IPage<OnlineRuleVo>> listOnlineColumnRule(OnlineColumn onlineColumn,
													   @RequestBody OnlineRuleDto onlineRuleDtoFilter,
													   @RequestBody MyOrderParam orderParam, Query query) {
		R<Void> verifyResult = this.doOnlineColumnRuleVerify(onlineColumn.getColumnId());
		if (!verifyResult.isSuccess()) {
			return R.fail(verifyResult.getMsg());
		}
		OnlineRule filter = MyModelUtil.copyTo(onlineRuleDtoFilter, OnlineRule.class);
		String orderBy = MyOrderParam.buildOrderBy(orderParam, OnlineRule.class);
		List<OnlineRule> onlineRuleList = onlineRuleService.getOnlineRuleListByColumnId(onlineColumn.getColumnId(), filter, orderBy);

		IPage<OnlineRule> pages = new Page<>(query.getCurrent(), query.getSize());
		pages.setRecords(onlineRuleList);

		return R.data(OnlineRuleWrapper.build().pageVO(pages));
	}

	/**
	 * 列出与指定字段数据存在多对多关系的 [验证规则] 列表数据。
	 *
	 * @param onlineColumn            主表关联字段。
	 * @return 应答结果对象，返回符合条件的数据列表。
	 */
	@GetMapping("/listOnlineColumnRuleNoPage")
	public R<List<OnlineRuleVo>> listOnlineColumnRuleNoPage( OnlineColumn onlineColumn) {
		R<Void> verifyResult = this.doOnlineColumnRuleVerify(onlineColumn.getColumnId());
		if (!verifyResult.isSuccess()) {
			return R.fail(verifyResult.getMsg());
		}
		OnlineRule filter = new OnlineRule();
		List<OnlineRule> onlineRuleList = onlineRuleService.getOnlineRuleListByColumnId(onlineColumn.getColumnId(), filter, null);

		return R.data(OnlineRuleWrapper.build().listVO(onlineRuleList));
	}

    private R<Void> doOnlineColumnRuleVerify(Long columnId) {
        if (CommonUtil.existBlankArgument(columnId)) {
            return R.fail(ErrorCodeEnum.ARGUMENT_NULL_EXIST.getErrorMessage());
        }
        if (onlineColumnService.getById(columnId) == null) {
            return R.fail(ErrorCodeEnum.INVALID_RELATED_RECORD_ID.getErrorMessage());
        }
        return R.data(null);
    }

    /**
     * 批量添加字段数据和 [验证规则] 对象的多对多关联关系数据。
     *
//     * @param columnId                主表主键Id。
//     * @param onlineColumnRuleDtoList 关联对象列表。
     * @return 应答结果对象。
     */
    @PostMapping("/addOnlineColumnRule")
	public R<Void> addOnlineColumnRule(@RequestBody OnlineColumnRuleDto onlineColumnRuleDto) {
		if (CommonUtil.existBlankArgument(onlineColumnRuleDto)) {
			return R.fail(ErrorCodeEnum.ARGUMENT_NULL_EXIST.getErrorMessage());
		}
		String errorMessage = CommonUtil.getModelValidationError(onlineColumnRuleDto);
		if (errorMessage != null) {
			return R.fail(errorMessage);
		}

		if (onlineColumnService.getById(onlineColumnRuleDto.getColumnId()) == null
			|| onlineColumnRuleDto.getRuleId() == null) {
			return R.fail(ErrorCodeEnum.INVALID_RELATED_RECORD_ID.getErrorMessage());
		}

		List<OnlineColumnRuleDto> onlineColumnRuleDtoList = new ArrayList<>();
		onlineColumnRuleDtoList.add(onlineColumnRuleDto);
		List<OnlineColumnRule> onlineColumnRuleList =
			MyModelUtil.copyCollectionTo(onlineColumnRuleDtoList, OnlineColumnRule.class);
		onlineColumnService.addOnlineColumnRuleList(onlineColumnRuleList, onlineColumnRuleDto.getColumnId());
		return R.data(null);
	}

    /**
     * 更新指定字段数据和指定 [验证规则] 的多对多关联数据。
     *
     * @param onlineColumnRuleDto 对多对中间表对象。
     * @return 应答结果对象。
     */
    @PostMapping("/updateOnlineColumnRule")
    public R<Void> updateOnlineColumnRule(
            @RequestBody OnlineColumnRuleDto onlineColumnRuleDto) {
        String errorMessage = CommonUtil.getModelValidationError(onlineColumnRuleDto);
        if (errorMessage != null) {
            return R.fail(errorMessage);
        }
        OnlineColumnRule onlineColumnRule = MyModelUtil.copyTo(onlineColumnRuleDto, OnlineColumnRule.class);
        if (!onlineColumnService.updateOnlineColumnRule(onlineColumnRule)) {
            return R.fail(ErrorCodeEnum.DATA_NOT_EXIST.getErrorMessage());
        }
        return R.data(null);
    }

    /**
     * 显示字段数据和指定 [验证规则] 的多对多关联详情数据。
     *
     * @param columnId 主表主键Id。
     * @param ruleId   从表主键Id。
     * @return 应答结果对象，包括中间表详情。
     */
    @GetMapping("/viewOnlineColumnRule")
    public R<OnlineColumnRuleVo> viewOnlineColumnRule(
		@RequestParam Long columnId, @RequestParam Long ruleId) {
        if (CommonUtil.existBlankArgument(columnId, ruleId)) {
            return R.fail(ErrorCodeEnum.ARGUMENT_NULL_EXIST.getErrorMessage());
        }
        OnlineColumnRule onlineColumnRule = onlineColumnService.getOnlineColumnRule(columnId, ruleId);
        if (onlineColumnRule == null) {
            return R.fail(ErrorCodeEnum.DATA_NOT_EXIST.getErrorMessage());
        }
        OnlineColumnRuleVo onlineColumnRuleVo = MyModelUtil.copyTo(onlineColumnRule, OnlineColumnRuleVo.class);
        return R.data(onlineColumnRuleVo);
    }

    /**
     * 移除指定字段数据和指定 [验证规则] 的多对多关联关系。
     *
     * @param columnId 主表主键Id。
     * @param ruleId   从表主键Id。
     * @return 应答结果对象。
     */
    @PostMapping("/deleteOnlineColumnRule")
    public R<Void> deleteOnlineColumnRule(
		@RequestBody Long columnId, @RequestBody Long ruleId) {
        if (CommonUtil.existBlankArgument(columnId, ruleId)) {
            return R.fail(ErrorCodeEnum.ARGUMENT_NULL_EXIST.getErrorMessage());
        }
        if (!onlineColumnService.removeOnlineColumnRule(columnId, ruleId)) {
            return R.fail(ErrorCodeEnum.DATA_NOT_EXIST.getErrorMessage());
        }
        return R.data(null);
    }

    /**
     * 以字典形式返回全部字段数据数据集合。字典的键值为[columnId, columnName]。
     * 白名单接口，登录用户均可访问。
     *
     * @param filter 过滤对象。
     * @return 应答结果对象，包含的数据为 List<Map<String, String>>，map中包含两条记录，key的值分别是id和name，value对应具体数据。
     */
    @GetMapping("/listDict")
    public R<List<Map<String, Object>>> listDict(OnlineColumn filter) {
        List<OnlineColumn> resultList = onlineColumnService.getOnlineColumnList(filter, null);
        return R.data(BeanQuery.select(
                "columnId as id", "columnName as name").executeFrom(resultList));
    }
}
